/**
 * @author João Luís Palma Cardeira - hippie.stereo@gmail.com
 * @version 1.0
 * @date 06/06/2013
 * @copyright (C) :-)
 * @note Applicação para o trabalho de EDA 2012/2013
 * @see class : BubbleSortCLS, RandomCLS, QuickSortCLS, HeapSortCLS, InsertionSortCLS, MergeSortCLS, PlotGraph
 */
import java.util.Scanner; 

public class RunApp
{

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */
	
	private static Scanner readUserInput = null;
	private  final String TitleX = "Elementos por lista";
	private final String TitleY = "Time - MilliSeconds";
	private final String labelDataTeoric = "Previsão Teórica";
	private final String labelDataXperiment = "Linha Experimental";
	private final String textMenuChoiceListType = "Tipo de listas ?\n\n[1] - Pequena (100, 200, 400, 600, 800)\n[2] - Média (1.000, 2.000, 3.000, 4.000, 5.000)\n[3] - Grande (6.000, 7.000, 8.000, 9.000, 10.000)";
	private final String textReadInt_1 = "\nQual o algoritmo ?\n\n[1] - BubbleSort\n[2] - QuickSort\n[3] - InsertionSort\n[4] - MergeSort\n[5] - HeapSort\n\nEscolha :\n";
	private final String textReadInt_2 = "\nSeleccionar Experiência :\n\nEscolha :\n";
	private final String TitlePlotBubble = "Algorithm - BubbleSort";
	private final String TitlePlotQuickSort = "Algorithm - QuickSort";
	private final String TitlePlotQuickRandomized = "Algorithm - RandomizedQuickSort";
	private final String TitlePlotQuickTail = "Algorithm - TailRecursiveQuickSort";
	private final String TitlePlotInsertion = "Algorithm - InsertionSort";
	private final String TitlePlotMerge = "Algorithm - MergeSort";
	private final String TitlePlotHeap = "Algorithm - HeapSort";
	private final String TextChoiceQuickType = "\nQual o tipo de sort ?\n\n[1] - Sort\n[2] - RandomizedQuicksort\n[3] - TailRecursiveQuicksort\n";
	// - Index = algorithm | Value = Lista Pequena ; Lista Media ; Lista Grande
	private int[] tabChoice = new int[5];
	private int typeAlgoToRun = 0;
	private BubbleSortCLS myBubbleSort;
	private QuickSortCLS myQuickSort;
	private InsertionSortCLS myInsertionSort;
	private MergeSortCLS myMergeSort;
	private HeapSortCLS myHeapSort;
	private int choiceQuickAlgoType = 0;

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */

	public static void main(String[] args)
	{
		RunApp myRun = new RunApp();
		myRun.doStart();
	}

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */
	
	private void doStart()
	{
		/* Read integer from console for nmenu choice */
		int readInt = readForInt(textReadInt_1, 1);

		/* MAIN SWITCH - START */
		switch (readInt)
		{
		/* BubbleSort */
	    case 1:
	    		System.out.println("\n--- BubbleSort ---\n");
				System.out.println(textMenuChoiceListType);
	    		readInt = readForInt(textReadInt_2, 2);
	    		typeAlgoToRun = 1;
				
				switch (readInt)
				{
					case 1:  
						tabChoice[0] = 1;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 2:  
						tabChoice[0] = 2;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 3:
						tabChoice[0] = 3;
						runCaseChoice(tabChoice,typeAlgoToRun);
						break;
					default: System.exit(0);
						break;
				}
	        break;
	    /* QuickSort */
	    case 2:
	    		System.out.println("\n--- QuickSort ---\n");
	    		choiceQuickAlgoType = readForInt(TextChoiceQuickType, 2);

				if (choiceQuickAlgoType == 1)
				{
					System.out.println("\nEscolha : 1 - Sort\n");
				}
				else if (choiceQuickAlgoType == 2)
				{
					System.out.println("\nEscolha : 2 - RandomizedQuicksort\n");
				}
				else if (choiceQuickAlgoType == 3)
				{
					System.out.println("\nEscolha : 3 -TailRecursiveQuicksort\n");
				}

				System.out.println(textMenuChoiceListType);
	    		readInt = readForInt(textReadInt_2, 2);
	    		typeAlgoToRun = 2;
				
				switch (readInt)
				{
					case 1: 
						tabChoice[1] = 1;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 2:  
						tabChoice[1] = 2;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 3:  
						tabChoice[1] = 3;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					default: System.exit(0);
						break;
				}
	    	break;
	    /* InsertionSort */
	    case 3:
	    		System.out.println("\n--- InsertionSort ---\n");
				System.out.println(textMenuChoiceListType);
	    		readInt = readForInt(textReadInt_2, 2);
	    		typeAlgoToRun = 3;
	    		
				switch (readInt)
				{
					case 1: 
						tabChoice[2] = 1;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 2:  
						tabChoice[2] = 2;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 3:  
						tabChoice[2] = 3;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					default: System.exit(0); 
						break;
				}
			break;
	    	/* MergeSort */
	    case 4:
	    		System.out.println("\n--- MergeSort ---\n");
				System.out.println(textMenuChoiceListType);
	    		readInt = readForInt(textReadInt_2, 2);
	    		typeAlgoToRun = 4;
	    		
				switch (readInt)
				{
					case 1: 
						tabChoice[3] = 1;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 2:  
						tabChoice[3] = 2;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 3:  
						tabChoice[3] = 3;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					default: System.exit(0);
						break;		
				}
	    	break;
		    /* HeapSort */
		    case 5:
		    	System.out.println("\n--- HeapSort ---\n");
				System.out.println(textMenuChoiceListType);
	    		readInt = readForInt(textReadInt_2, 2);
	    		typeAlgoToRun = 5;
	    		
				switch (readInt)
				{
					case 1: 
						tabChoice[4] = 1;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 2:  
						tabChoice[4] = 2;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					case 3:  
						tabChoice[4] = 3;
						runCaseChoice(tabChoice, typeAlgoToRun);
						break;
					default: System.exit(0);
						break;
				}
	    	break;	    	
		    default:
		    	System.exit(0);
	    	break;
		}
		/* MAIN SWITCH - END */
	}

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */
		
	private static int readForInt(String textToConsole, int checkLevel)
	{
		readUserInput = new Scanner(System.in);
		System.out.println(textToConsole);
		String myLine = readUserInput.nextLine();
		
		if((!(Integer.parseInt(myLine) >= 1 && Integer.parseInt(myLine) <= 5)) && checkLevel == 1)
		{
			readUserInput.close();
			System.exit(0);
		}
		else if((!(Integer.parseInt(myLine) >= 1 && Integer.parseInt(myLine) <= 3)) && checkLevel == 2)
		{
			readUserInput.close();
			System.exit(0);			
		}
		
		return Integer.parseInt(myLine);
	}

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */
	
	private void runCaseChoice(int[] tabChoice, int typeAlgoToRun)
	{
		double listLowValue[] = {100, 200, 400, 600, 800};
		double listMedValue[] = {1000, 2000, 3000, 4000, 5000};
		double listMaxValue[] = {6000, 7000, 8000, 9000, 10000};
		
		/* BUBBLE SORT */		
		if(typeAlgoToRun == 1)
		{
			if(tabChoice[0] == 1)
			{
		    	String imgNameBubble_1 = "BubbleSort Lista Pequena";			
		    	runSortChoice(listLowValue, imgNameBubble_1, typeAlgoToRun);
			}
			else if(tabChoice[0] == 2)
			{
		    	String imgNameBubble_2 = "BubbleSort Lista Media";			
		    	runSortChoice(listMedValue, imgNameBubble_2, typeAlgoToRun);
			}
			else if(tabChoice[0] == 3)
			{
		    	String imgNameBubble_3 = "BubbleSort Lista Grande";			
		    	runSortChoice(listMaxValue, imgNameBubble_3, typeAlgoToRun);
			}	
		}
		/* QUICK SORT */
		else if(typeAlgoToRun == 2)
		{
			// - 
			if (choiceQuickAlgoType == 1)
			{
				if(tabChoice[1] == 1)
				{
					String imgNameQuick_1 = "QuickSort Lista Pequena";		
			    	runSortChoice(listLowValue, imgNameQuick_1, typeAlgoToRun);								
				}
				else if(tabChoice[1] == 2)
				{
					String imgNameQuick_2 = "QuickSort Lista Media";			
			    	runSortChoice(listMedValue, imgNameQuick_2, typeAlgoToRun);											
				}
				else if(tabChoice[1] == 3)
				{
					String imgNameQuick_3 = "QuickSort Lista Grande";	
			    	runSortChoice(listMaxValue, imgNameQuick_3, typeAlgoToRun);
				}
			}
			else if (choiceQuickAlgoType == 2)
			{
				if(tabChoice[1] == 1)
				{
			    	String imgNameQuick_1 = "RandomizedQuicksort Lista Pequena";		
			    	runSortChoice(listLowValue, imgNameQuick_1, typeAlgoToRun);								
				}
				else if(tabChoice[1] == 2)
				{
			    	String imgNameQuick_2 = "RandomizedQuicksort Lista Media";			
			    	runSortChoice(listMedValue, imgNameQuick_2, typeAlgoToRun);											
				}
				else if(tabChoice[1] == 3)
				{
			    	String imgNameQuick_3 = "RandomizedQuicksort Lista Grande";	
			    	runSortChoice(listMaxValue, imgNameQuick_3, typeAlgoToRun);
				}
			}
			else if (choiceQuickAlgoType == 3)
			{
				if(tabChoice[1] == 1)
				{
			    	String imgNameQuick_1 = "TailRecursiveQuicksort Lista Pequena";		
			    	runSortChoice(listLowValue, imgNameQuick_1, typeAlgoToRun);								
				}
				else if(tabChoice[1] == 2)
				{
			    	String imgNameQuick_2 = "TailRecursiveQuicksort Lista Media";			
			    	runSortChoice(listMedValue, imgNameQuick_2, typeAlgoToRun);											
				}
				else if(tabChoice[1] == 3)
				{
			    	String imgNameQuick_3 = "TailRecursiveQuicksort Lista Grande";	
			    	runSortChoice(listMaxValue, imgNameQuick_3, typeAlgoToRun);
				}
			}
		}
		/* INSERTION SORT */
		else if(typeAlgoToRun == 3)
		{
			if(tabChoice[2] == 1)
			{
		    	String imgNameInsertion_1 = "InsertionSort Lista Pequena";	
		    	runSortChoice(listLowValue, imgNameInsertion_1, typeAlgoToRun);
			}
			else if(tabChoice[2] == 2)
			{
		    	String imgNameInsertion_2 = "InsertionSort Lista Media";	
		    	runSortChoice(listMedValue, imgNameInsertion_2, typeAlgoToRun);
			}
			else if(tabChoice[2] == 3)
			{
		    	String imgNameInsertion_3 = "InsertionSort Lista Grande";
		    	runSortChoice(listMaxValue, imgNameInsertion_3, typeAlgoToRun);
			}
		}
		/* MERGE SORT */
		else if(typeAlgoToRun == 4)
		{
			if(tabChoice[3] == 1)
			{
		    	String imgNameMerge_1 = "MergeSort Lista Pequena";			
		    	runSortChoice(listLowValue, imgNameMerge_1, typeAlgoToRun);
			}
			else if(tabChoice[3] == 2)
			{
		    	String imgNameMerge_2 = "MergeSort Lista Media";		
		    	runSortChoice(listMedValue, imgNameMerge_2, typeAlgoToRun);
			}
			else if(tabChoice[3] == 3)
			{
		    	String imgNameMerge_3 = "MergeSort Lista Grande";	
		    	runSortChoice(listMaxValue, imgNameMerge_3, typeAlgoToRun);
			}
		}
		/* HEAP SORT */
		else if(typeAlgoToRun == 5)
		{
			if(tabChoice[4] == 1)
			{
		    	String imgNameHeap_1 = "HeapSort Lista Pequena";			
		    	runSortChoice(listLowValue, imgNameHeap_1, typeAlgoToRun);
			}
			else if(tabChoice[4] == 2)
			{
		    	String imgNameHeap_2 = "HeapSort Lista Media";		
		    	runSortChoice(listMedValue, imgNameHeap_2, typeAlgoToRun);
			}
			else if(tabChoice[4] == 3)
			{
		    	String imgNameHeap_3 = "HeapSort Lista Grande";		
		    	runSortChoice(listMaxValue, imgNameHeap_3, typeAlgoToRun);
			}
		}
	}

	/** 
	 * nomMethode - XXX
	 * @return [description]
	 * @param [parameter-name] [description]
	 * @param [parameter-name] [description]
	 * @exception   Exception1  description de la première exception 
	 * @see UneAutreClasse#UneAutreMethode 
	 */
	
	private void runSortChoice(double listNumbers[], String imageName, int algoChoice)
	{	
		/* Bubble Sort Object */
		if(algoChoice == 1)
		{myBubbleSort = new BubbleSortCLS();}
		/* Quick Sort Object */
		else if(algoChoice == 2)
		{myQuickSort = new QuickSortCLS();}
		/* Insertion Sort Object */
		else if(algoChoice == 3)
		{myInsertionSort = new InsertionSortCLS();}
		/* Merge Sort Object */
		else if(algoChoice == 4)
		{myMergeSort = new MergeSortCLS();}
		/* Heap Sort Object */
		else if(algoChoice == 5)
		{myHeapSort = new HeapSortCLS();}

		// - XXX
		
		/* Repeat the sort algo X times */
		int timesDoSort = 30;
		/* Results in seconds for sorting the list one time */
		double listTimes[] = null;
		double listConstant[] = new double[listNumbers.length];
		/* Teoric data for plot Y */
		double[] yDataTeoric = null;
		/* Experimental data for plot Y */
		double[] yDataXperiment = new double[listNumbers.length];
		double newListRan[] = null;
		double dblMedia = 0;
		double dblConstant = 0;
		
		for (int i = 0; i < listNumbers.length; i++)
		{
			/* New list for results */
			listTimes = new double[timesDoSort];
			/*  */
			for (int j = 0; j < timesDoSort; j++)
			{
				/* Fill new list with random double, quantity from list input */
				RandomCLS makeRan = new RandomCLS();
				newListRan = makeRan.fillListRandom(listNumbers[i], 1.01, 1.99);
				long startTime = System.currentTimeMillis();
				
				if(algoChoice == 1)
				{myBubbleSort.funcBubbleSort(newListRan);}
				else if(algoChoice == 2)
				{
					if (choiceQuickAlgoType == 1)
					{
						myQuickSort.QuickSort(newListRan, 0, newListRan.length - 1);
					}
					else if (choiceQuickAlgoType == 2)
					{
						myQuickSort.RandomizedQuicksort(newListRan, 0, newListRan.length - 1);
					}
					else if (choiceQuickAlgoType == 3)
					{
						myQuickSort.TailRecursiveQuicksort(newListRan, 0, newListRan.length - 1);
					}
				}
				else if(algoChoice == 3)
				{myInsertionSort.funcInsertionSort(newListRan);}
				else if(algoChoice == 4)
				{myMergeSort.MergeSort(newListRan, 1, newListRan.length - 1);}
				else if(algoChoice == 5)
				{myHeapSort.Sort(newListRan);}	 
				
				long endTime = System.currentTimeMillis();
				listTimes[j] = (double)(endTime - startTime);
			}	
			
			for (int a = 0; a < listTimes.length; a++)
			{
				dblMedia += listTimes[a];
			}
			
			yDataXperiment[i] =  dblMedia / listTimes.length;
		}
		
		for (int i = 0; i < listConstant.length; i++)
		{
			if(algoChoice == 1)
			{listConstant[i] = yDataXperiment[i] / Math.pow(listNumbers[i], 2);}
			else if(algoChoice == 2)
			{listConstant[i] = yDataXperiment[i] / (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
			else if(algoChoice == 3)
			{listConstant[i] = yDataXperiment[i] / Math.pow(listNumbers[i], 2);}
			else if(algoChoice == 4)
			{listConstant[i] = yDataXperiment[i] / (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
			else if(algoChoice == 5)
			{listConstant[i] = yDataXperiment[i] / (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
			
			dblConstant += listConstant[i];
		}
		
		dblConstant = dblConstant / listConstant.length;
		yDataTeoric = new double[listNumbers.length];

		for (int i = 0; i < listNumbers.length; i++)
		{
			if(algoChoice == 1)
			{yDataTeoric[i] = dblConstant * (Math.pow(listNumbers[i], 2));}
			else if(algoChoice == 2)
			{yDataTeoric[i] = dblConstant * (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
			else if(algoChoice == 3)
			{yDataTeoric[i] = dblConstant * (Math.pow(listNumbers[i], 2));}
			else if(algoChoice == 4)
			{yDataTeoric[i] = dblConstant * (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
			else if(algoChoice == 5)
			{yDataTeoric[i] = dblConstant * (listNumbers[i] * (Math.log(listNumbers[i])/Math.log(2)));}
		}		
		
		PlotGraph myPlot = new PlotGraph(imageName, 800, 600, listNumbers, yDataTeoric, yDataXperiment);
		
		if(algoChoice == 1)
		{
			String TitlePlot = TitlePlotBubble;
			myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
		}
		else if(algoChoice == 2)
		{
			if (choiceQuickAlgoType == 1)
			{
				String TitlePlot = TitlePlotQuickSort;
				myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
			}
			else if (choiceQuickAlgoType == 2)
			{
				String TitlePlot = TitlePlotQuickRandomized;
				myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
			}
			else if (choiceQuickAlgoType == 3)
			{
				String TitlePlot = TitlePlotQuickTail;
				myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
			}
		}
		else if(algoChoice == 3)
		{
			String TitlePlot = TitlePlotInsertion;
			myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
		}
		else if(algoChoice == 4)
		{
			String TitlePlot = TitlePlotMerge;
			myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
		}
		else if(algoChoice == 5)
		{
			String TitlePlot = TitlePlotHeap;
			myPlot.doPlot(TitlePlot, TitleX, TitleY, labelDataTeoric, labelDataXperiment);
		}
		  
		// - Save Plot to HDD.
		if(myPlot.savePng()){System.out.println("\nImagem \"" + imageName + "\".png Gravada.");}

	}
}